#include "tapi32u8.h"
#include "tapi32v.h"
#include "tmisc.h"
#include <stddef.h>

#define SafeDeleteArrary( pArrary ) { if( pArrary ){ delete[] pArrary; pArrary = NULL; } }

WCHAR *U8toW( const char* src, bool noStatic )
{
	static WCHAR* _wbuf = NULL;

	WCHAR*	 wtmp = NULL;
	WCHAR*&	 wbuf = noStatic ? wtmp : _wbuf;
	SafeDeleteArrary( wbuf );

	int len = U8toW( src, NULL, 0 );
	if( len > 0 )
	{
		wbuf = new WCHAR[len];
		U8toW( src,wbuf, len );
	}
	return wbuf;
}

char* WtoU8( const WCHAR* src, bool noStatic )
{
	static char* _buf = NULL;

	char*	tmp = NULL;
	char*&	buf = noStatic ? tmp : _buf;
	SafeDeleteArrary( buf );

	int len = WtoU8( src, NULL, 0 );
	if( len > 0 )
	{
		buf = new char[len];
		WtoU8( src, buf, len );
	}
	return buf;
}

char *WtoA( const WCHAR* src, bool noStatic )
{
	static char* _buf = NULL;

	char*	tmp = NULL;
	char*&	buf = noStatic ? tmp : _buf;
	SafeDeleteArrary( buf );
	
	int len = WtoA( src, NULL, 0 );
	if( len > 0 )
	{
		buf = new char[len];
		WtoA( src, buf, len );
	}
	return buf;
}

char* AtoU8( const char* src, bool noStatic )
{
	static char* _buf = NULL;

	char*	tmp = NULL;
	char*&	buf = noStatic ? tmp : _buf;
	SafeDeleteArrary( buf );

	WCHAR* wsrc = AtoW( src, true );
	if( wsrc ) buf = WtoU8( wsrc, true );
	SafeDeleteArrary( wsrc );
	return buf;
}

char* U8toA( const char* src, bool noStatic )
{
	static char* _buf = NULL;
	
	char*	tmp = NULL;
	char*&	buf = noStatic ? tmp : _buf;
	SafeDeleteArrary( buf );

	WCHAR* wsrc = U8toW( src, true );
	if( wsrc ) buf = WtoA( wsrc, true );
	SafeDeleteArrary( wsrc );
	return buf; 
}

char *toA( const void* src, bool noStatic )
{
	return TAPI32V::IS_WINNT_V ? WtoA( (WCHAR*)src, noStatic ) : (char*)( noStatic ? _strdup((const char*)src) : src );
}

WCHAR *toW( const void* src, bool noStatic )
{
	return TAPI32V::IS_WINNT_V ? AtoW( (char*)src, noStatic ) : (WCHAR*)( noStatic ? TAPI32V::strdupV(src) : src );
}

void *toV( const char* src, bool noStatic )
{
	return TAPI32V::IS_WINNT_V ? AtoW( src, noStatic ) : ( noStatic ? TAPI32V::strdupV(src) : (void*)src );
}

void *toV( const WCHAR* src, bool noStatic )
{
	return TAPI32V::IS_WINNT_V ? ( noStatic ? TAPI32V::strdupV(src) : (void*)src ) : WtoA( src, noStatic );
}

bool IsUTF8( const char* s )
{
	const u_char* str = ( const u_char*)s;
	while( *str )
	{
		if( *str <= 0x7f ){}
		else if( *str <= 0xdf )
		{	
			if( (*++s & 0xc0 ) != 0x80 ) return false; 
		}
		else if( *str <= 0xef )
		{
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
		}
		else if( *str <= 0xf7 )
		{
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
		}
		else if( *str <= 0xfb )
		{
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
		}
		else if( *str <= 0xfd )
		{
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
			if( (*++s & 0xc0 ) != 0x80 ) return false;
		}
		++str;			
	}
	return true;
}

HWND CreateWindowU8( const char* class_name, const char* window_name, DWORD style, 
					int x, int y, int width, int height, HWND hParent, HMENU hMenu, 
					HINSTANCE hInst, void* param )
{
	Wstr classNameW( class_name );
	Wstr windowNameW( window_name );
	return ::CreateWindowW( classNameW, windowNameW, style, x, y, width, height, hParent, hMenu, hInst, param );
}

HWND FindWindowU8( const char* class_name, const char* window_name )
{
	Wstr classNameW( class_name );
	Wstr windowNameW( window_name );
	return ::FindWindowW( classNameW, windowNameW );
}

BOOL AppendMenuU8( HMENU hMenu, UINT flags, UINT idItem, const char* item_str)
{
	return FALSE;
}

BOOL InsertMenuU8( HMENU hMenu, UINT idItem, UINT flags, UINT idNewItem, const char* item_str )
{
	return FALSE;
}

BOOL ModifyMenuU8( HMENU hMenu, UINT idItem, UINT flags, UINT idNewItem, const char* item_str )
{
	return FALSE;
}

DWORD GetFileAttributesU8( const char* path )
{
	Wstr wpath( path );
	return ::GetFileAttributesW( wpath );
}

BOOL SetFileAttributesU8( const char* path, DWORD attr )
{
	Wstr wpath( path );
	return ::SetFileAttributesW( wpath, attr );
}

void WIN32_FIND_DATA_WtoU8( const WIN32_FIND_DATAW *fdat_w, WIN32_FIND_DATA_U8 *fdat_u8, BOOL include_fname )
{
	memcpy( fdat_u8, fdat_w, offsetof(WIN32_FIND_DATAW, cFileName) );
	if( include_fname )
	{
		WtoU8( fdat_w->cFileName, fdat_u8->cFileName, sizeof(fdat_u8->cFileName) );
		WtoU8( fdat_w->cAlternateFileName, fdat_u8->cAlternateFileName, sizeof( fdat_u8->cAlternateFileName) );
	}
}
HANDLE FindFirstFileU8( const char* path, WIN32_FIND_DATA_U8 *fdat )
{
	Wstr	wpath( path );

	WIN32_FIND_DATAW fdata;
	HANDLE hFile = ::FindFirstFileW( wpath, &fdata );
	if( hFile != INVALID_HANDLE_VALUE )
		WIN32_FIND_DATA_WtoU8( &fdata, fdat );
	return hFile;
}

BOOL FindNextFileU8( HANDLE hDir, WIN32_FIND_DATA_U8 *fdat )
{
	WIN32_FIND_DATAW fData;
	BOOL ret = ::FindNextFileW( hDir, &fData );
	if( ret ) WIN32_FIND_DATA_WtoU8( &fData, fdat );
	return ret;
}

DWORD GetFullPathNameU8( const char* path, DWORD size, char* buf, char** fname )
{
	Wstr wpath( path );
	Wstr wbuf( size );
	WCHAR* wfilename = NULL;
	
	DWORD ret = ::GetFullPathNameW( wpath, size, wbuf.Buf(), &wfilename );
	if( ( ret == 0 )| ( ret > size ) ) return ret;

	int fileNameLen = wfilename ? WtoU8( wfilename, buf, size ) : 0;
	int pathLen = WtoU8( wbuf, buf, size );
	*fname = wfilename ? ( buf + pathLen - fileNameLen ) : NULL;
	return ret; 
	
}

HANDLE CreateFileU8( const char* path, DWORD access_flg, DWORD share_flg,
					SECURITY_ATTRIBUTES *sa, DWORD create_flg, DWORD attr_flg, HANDLE hTemplate )
{
	Wstr wpath( path );
	return ::CreateFileW( wpath, access_flg, share_flg, sa, create_flg, attr_flg, hTemplate );
}

LPSTR GetLoadStrU8( UINT resId, HINSTANCE hInstance )
{
	extern HINSTANCE defaultStrInstance;
	static TResHash* hash = NULL;
	
	if( hash == NULL )
		hash = new TResHash( 100 );

	WCHAR buf[1024] = { 0 };
	TResHashObj* obj = hash->Search( resId );
	if( obj == NULL )
	{
		if( ::LoadStringW( hInstance ? hInstance : defaultStrInstance, resId, buf, sizeof(buf)/sizeof(WCHAR) ) >= 0 )
		{
			U8Str bufU8( buf );
			obj = new TResHashObj( resId, _strdup( bufU8 ) );
			hash->Register( obj );
		}
	}
	return obj ? (char*)obj->_val : NULL;
}

HINSTANCE ShellExecuteU8(HWND hWnd, LPCSTR op, LPCSTR file, LPSTR params, LPCSTR dir, int nShow)
{
	Wstr	op_w(op), file_w(file), params_w(params), dir_w(dir);
	return	::ShellExecuteW(hWnd, op_w, file_w, params_w, dir_w, nShow);
}

BOOL ShellExecuteExU8(SHELLEXECUTEINFO *info)
{
	SHELLEXECUTEINFOW	info_w;
	memcpy(&info_w, info, sizeof(SHELLEXECUTEINFO));
	Wstr	verb_w(info->lpVerb), file_w(info->lpFile), param_w(info->lpParameters),
		dir_w(info->lpDirectory), class_w(info->lpClass);

	info_w.lpVerb		= verb_w;
	info_w.lpFile		= file_w;
	info_w.lpParameters	= param_w;
	info_w.lpDirectory	= dir_w;
	info_w.lpClass		= class_w;

	BOOL	ret = ::ShellExecuteExW(&info_w);

	info_w.lpFile		= (WCHAR *)info->lpFile;
	info_w.lpParameters	= (WCHAR *)info->lpParameters;
	info_w.lpDirectory	= (WCHAR *)info->lpDirectory;
	info_w.lpClass		= (WCHAR *)info->lpClass;
	memcpy(info, &info_w, sizeof(SHELLEXECUTEINFO));

	return	ret;
}
